/*
 * Copyright (C) 2016 FarmFriend Co., Ltd. All rights reserved.
 */

package com.tsingteng.cosfun.crashUtils.utils;

import com.tsingteng.cosfun.app.AppContext;

import android.os.Build;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;


public class FileUtils {

    private static final String TAG = "FileUtils";

    /**
     * Get root directory for current app on external storage.
     * <p></p>
     * Note for Android document:
     * Starting in Android 4.4, multiple external storage devices are surfaced to developers
     * through Context.getExternalFilesDirs(), Context.getExternalCacheDirs()
     * and Context.getObbDirs().
     * External storage devices surfaced through these APIs must be a semi-permanent part of the
     * device (such as an SD card slot in a battery compartment). Developers expect data stored
     * in these locations to be available over long periods of time. For this reason, transient
     * storage devices (such as USB mass storage drives) should not be surfaced through these APIs.
     * The WRITE_EXTERNAL_STORAGE permission must only grant write access to the primary external
     * storage on a device. Apps must not be allowed to write to secondary external storage
     * devices, except in their package-specific directories as allowed by synthesized permissions.
     * Restricting writes in this way ensures the system can clean up files when applications
     * are uninstalled.
     */
    public static File getAppRootDirectoryOnExternalStorage() {
        File appRootDir;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            appRootDir = AppContext.getContext()
                .getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
            if (appRootDir != null && appRootDir.canWrite()) {
                return appRootDir;
            }
        }
        appRootDir = Environment.getExternalStorageDirectory();
        if (appRootDir != null && appRootDir.canWrite()) {
            return appRootDir;
        }
        throw new RuntimeException("no writable directory found for this app!");
    }

    /**
     * @return 文件外部存储文字.
     */
    public static File getAppPictureDirectoryOnExternalStorage() {
        File appPicDir;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            appPicDir = AppContext.getContext()
                .getExternalFilesDir(Environment.DIRECTORY_PICTURES);
            if (appPicDir != null && appPicDir.canWrite()) {
                return appPicDir;
            }
        }
        appPicDir = new File(Environment.getExternalStorageDirectory(), "pictures");

        try {
            if (appPicDir.isFile()) {
                appPicDir.delete();
            }
        } catch (Exception ignored) {
            ignored.fillInStackTrace();
        }

        try {
            appPicDir.mkdirs();
        } catch (Exception ignored) {
            ignored.fillInStackTrace();
        }

        if (appPicDir.canWrite()) {
            return appPicDir;
        }
        throw new RuntimeException("no writable picture directory found for this app!");
    }

    public static File getAppSignPictureDirectoryOnExternalStorage() {
        File appPicDir;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            appPicDir = AppContext.getContext()
                .getExternalFilesDir(Environment.DIRECTORY_PICTURES);
            if (appPicDir != null && appPicDir.canWrite()) {
                appPicDir = new File(appPicDir, "clue");
            }
        } else {
            appPicDir = new File(Environment.getExternalStorageDirectory(), "pictures");
        }

        try {
            if (appPicDir.isFile()) {
                appPicDir.delete();
            }
        } catch (Exception ignored) {
        }

        try {
            appPicDir.mkdirs();
        } catch (Exception ignored) {
        }

        if (appPicDir.canWrite()) {
            return appPicDir;
        }
        throw new RuntimeException("no writable picture directory found for this app!");
    }

    /**
     * @return File app外部存储位置.
     */
    public static File getAppTempDirectoryOnExternalStorage() {
        File tempDir = new File(getAppRootDirectoryOnExternalStorage(), "temp");
        tempDir.mkdirs();
        return tempDir;
    }

    /**
     * Copy file from srcPath to dstPath.
     *
     * @param srcPath Full name of the file to be copied.
     * @param dstPath Full name of the destination file.
     * @throws IOException 抛出io异常.
     */
    public static void copyFile2DestPath(String srcPath, String dstPath) throws IOException {
        if (null == srcPath || null == dstPath) {
            return;
        }

        if (srcPath.equals(dstPath)) {
            return;
        }

        File srcFile = new File(srcPath);
        if (!srcFile.exists() || !srcFile.isFile()) {
            return;
        }

        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            File dstFile = new File(dstPath);
            File dstDir = dstFile.getParentFile();
            if (!dstDir.exists() && !dstDir.mkdirs()) {
                throw new IOException("fail to mkdirs " + dstPath);
            }

            if (!dstFile.exists() && !dstFile.createNewFile()) {
                throw new IOException("fail to create inexistent " + dstPath);
            } else if (dstFile.exists() && !dstFile.delete()) {
                throw new IOException("fail to remove existent " + dstPath);
            }

            fis = new FileInputStream(srcPath);
            fos = new FileOutputStream(dstPath);

            byte[] buffer = null;

            int bufferSize = 128 * 1024;
            do {
                bufferSize /= 2;
                try {
                    buffer = new byte[bufferSize];
                } catch (OutOfMemoryError e) {
                    if (bufferSize < 16) {
                        throw e;
                    }
                }
            } while (null == buffer);

            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, bytesRead);
            }
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException ignored) {
                ignored.printStackTrace();
            }

            try {
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException ignored) {
                ignored.printStackTrace();
            }
        }
    }

    /**
     * @param src      文件名称
     * @param position 位置.
     */
    public static void truncateFileFromPosition(File src, long position) {
        File tempFile = new File(src.getAbsolutePath() + ".temp");
        try {
            FileInputStream fis = new FileInputStream(src);
            FileOutputStream fos = new FileOutputStream(tempFile);

            fis.skip(position);
            byte[] buffer = new byte[16 * 1024];
            int count;
            while ((count = fis.read(buffer)) > 0) {
                fos.write(buffer, 0, count);
            }
            fis.close();
            fos.close();
            src.delete();
            tempFile.renameTo(src);
        } catch (Exception e) {
            Log.e(TAG, "truncate " + src.getAbsolutePath()
                + " from " + position + " fail, err=" + e);
        }
    }

    /**
     * 删除文件.
     */
    public static boolean deleteFile(String file) {
        if (TextUtils.isEmpty(file)) {
            return false;
        }
        File file1 = new File(file);
        return file1.delete() && file1.exists();
    }

    /**
     * 往指定文件中写内容.
     *
     * @param fileFullPath 指定文件路径.
     * @param content      内容.
     */
    public static void writeContent(String fileFullPath, String content) {
        if (TextUtils.isEmpty(fileFullPath)) {
            return;
        }
        File srcFile = new File(fileFullPath);
        if (srcFile.isDirectory()) {
            return;
        }
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(srcFile);
            fos.write(content.getBytes(), 0, content.getBytes().length);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.flush();
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 获取指定文件中写内容.
     *
     * @param fileFullPath 指定文件路径.
     */
    public static String getFileContent(String fileFullPath) {
        if (TextUtils.isEmpty(fileFullPath)) {
            return "";
        }
        File srcFile = new File(fileFullPath);
        if (!srcFile.isFile() || !srcFile.exists()) {
            return "";
        }
        BufferedReader fos = null;
        StringBuilder stringBuilder = new StringBuilder();
        try {
            fos = new BufferedReader(new InputStreamReader(new FileInputStream(srcFile)));
            String str;
            while ((str = fos.readLine()) != null) {
                stringBuilder.append(str);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return stringBuilder.toString();
    }
}
